/******************************************************************
 *
 *	CyberHTTP for Java
 *
 *	Copyright (C) Satoshi Konno 2002-2003
 *
 *	File: HostInterface.java
 *
 *	Revision;
 *
 *	05/12/03
 *		- first revision.
 *	05/13/03
 *		- Added support for IPv6 and loopback address.
 *	02/15/04
 *		- Added the following methods to set only a interface.
 *		- setInterface(), getInterfaces(), hasAssignedInterface()
 *	06/30/04
 *		- Moved the package from org.cybergarage.http to org.cybergarage.net.
 *	06/30/04
 *		- Theo Beisch <theo.beisch@gmx.de>
 *		- Changed isUseAddress() to isUsableAddress().
 *	
 ******************************************************************/

package org.cybergarage.net;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class HostInterface
{
    // //////////////////////////////////////////////
    // Constants
    // //////////////////////////////////////////////

    public static boolean USE_LOOPBACK_ADDR  = false;
    public static boolean USE_ONLY_IPV4_ADDR = false;
    public static boolean USE_ONLY_IPV6_ADDR = false;

    // //////////////////////////////////////////////
    // Network Interfaces
    // //////////////////////////////////////////////

    private static String ifAddress          = "";

    public final static void setInterface(String ifaddr)
    {
        ifAddress = ifaddr;
    }

    public final static String getInterface()
    {
        return ifAddress;
    }

    private final static boolean hasAssignedInterface()
    {
        return (0 < ifAddress.length()) ? true : false;
    }

    // //////////////////////////////////////////////
    // Network Interfaces
    // //////////////////////////////////////////////

    // Thanks for Theo Beisch (10/27/04)

    private final static boolean isUsableAddress(InetAddress addr)
    {
        if (USE_LOOPBACK_ADDR == false)
        {
            if (addr.isLoopbackAddress() == true)
                return false;
        }
        if (USE_ONLY_IPV4_ADDR == true)
        {
            if (addr instanceof Inet6Address)
                return false;
        }
        if (USE_ONLY_IPV6_ADDR == true)
        {
            if (addr instanceof Inet4Address)
                return false;
        }
        return true;
    }

    public final static int getNHostAddresses()
    {
        if (hasAssignedInterface() == true)
            return 1;

        int nHostAddrs = 0;
        try
        {
            Enumeration nis = NetworkInterface.getNetworkInterfaces();
            while (nis.hasMoreElements())
            {
                NetworkInterface ni = (NetworkInterface) nis.nextElement();
                Enumeration addrs = ni.getInetAddresses();
                while (addrs.hasMoreElements())
                {
                    InetAddress addr = (InetAddress) addrs.nextElement();
                    if (isUsableAddress(addr) == false)
                        continue;
                    nHostAddrs++ ;
                }
            }
        }
        catch (Exception e)
        {
        }
        ;
        return nHostAddrs;
    }

    public final static String getHostAddress(int n)
    {
        if (hasAssignedInterface() == true)
            return getInterface();

        int hostAddrCnt = 0;
        try
        {
            Enumeration nis = NetworkInterface.getNetworkInterfaces();
            while (nis.hasMoreElements())
            {
                NetworkInterface ni = (NetworkInterface) nis.nextElement();
                Enumeration addrs = ni.getInetAddresses();
                while (addrs.hasMoreElements())
                {
                    InetAddress addr = (InetAddress) addrs.nextElement();
                    if (isUsableAddress(addr) == false)
                        continue;
                    if (hostAddrCnt < n)
                    {
                        hostAddrCnt++ ;
                        continue;
                    }
                    String host = addr.getHostAddress();
                    // if (addr instanceof Inet6Address)
                    // host = "[" + host + "]";
                    return host;
                }
            }
        }
        catch (Exception e)
        {
        }
        ;
        return "";
    }

    // //////////////////////////////////////////////
    // isIPv?Address
    // //////////////////////////////////////////////

    public final static boolean isIPv6Address(String host)
    {
        try
        {
            InetAddress addr = InetAddress.getByName(host);
            if (addr instanceof Inet6Address)
                return true;
            return false;
        }
        catch (Exception e)
        {
        }
        return false;
    }

    public final static boolean isIPv4Address(String host)
    {
        try
        {
            InetAddress addr = InetAddress.getByName(host);
            if (addr instanceof Inet4Address)
                return true;
            return false;
        }
        catch (Exception e)
        {
        }
        return false;
    }

    // //////////////////////////////////////////////
    // hasIPv?Interfaces
    // //////////////////////////////////////////////

    public final static boolean hasIPv4Addresses()
    {
        int addrCnt = getNHostAddresses();
        for (int n = 0; n < addrCnt; n++ )
        {
            String addr = getHostAddress(n);
            if (isIPv4Address(addr) == true)
                return true;
        }
        return false;
    }

    public final static boolean hasIPv6Addresses()
    {
        int addrCnt = getNHostAddresses();
        for (int n = 0; n < addrCnt; n++ )
        {
            String addr = getHostAddress(n);
            if (isIPv6Address(addr) == true)
                return true;
        }
        return false;
    }

    // //////////////////////////////////////////////
    // hasIPv?Interfaces
    // //////////////////////////////////////////////

    public final static String getIPv4Address()
    {
        int addrCnt = getNHostAddresses();
        for (int n = 0; n < addrCnt; n++ )
        {
            String addr = getHostAddress(n);
            if (isIPv4Address(addr) == true)
                return addr;
        }
        return "";
    }

    public final static String getIPv6Address()
    {
        int addrCnt = getNHostAddresses();
        for (int n = 0; n < addrCnt; n++ )
        {
            String addr = getHostAddress(n);
            if (isIPv6Address(addr) == true)
                return addr;
        }
        return "";
    }

    // //////////////////////////////////////////////
    // getHostURL
    // //////////////////////////////////////////////

    public final static String getHostURL(String host, int port, String uri)
    {
        String hostAddr = host;
        if (isIPv6Address(host) == true)
            hostAddr = "[" + host + "]";
        return "http://" + hostAddr + ":" + Integer.toString(port) + uri;
    }

}
